package com.ygqh.baby.service.impl;

import com.foxinmy.weixin4j.util.StringUtil;
import com.ygqh.baby.ao.*;
import com.ygqh.baby.mapper.YgFortuneBagMapper;
import com.ygqh.baby.model.FortuneBagDetailVo;
import com.ygqh.baby.model.FortuneBagVo;
import com.ygqh.baby.model.SkuBasicData;
import com.ygqh.baby.po.YgFortuneBag;
import com.ygqh.baby.po.YgFortuneBagExample;
import com.ygqh.baby.service.YgFortuneBagService;
import com.ygqh.baby.service.YgSkuService;
import com.ygqh.baby.template.AbstractSplitListTemplate;
import com.ygqh.baby.utils.DateConvertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
public class YgFortuneBagServiceImpl implements YgFortuneBagService {

    @Autowired
    private YgFortuneBagMapper ygFortuneBagMapper;
    @Autowired
    private YgSkuService ygSkuService;

    @Override
    public List<YgFortuneBag> find() {
        YgFortuneBagExample example = new YgFortuneBagExample();
        example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        return ygFortuneBagMapper.selectByExample(example);
    }

    @Override
    public int findCount() {
        YgFortuneBagExample example = new YgFortuneBagExample();
        example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        return ygFortuneBagMapper.countByExample(example);
    }

    @Override
    public YgFortuneBag findById(Long id) {
        return ygFortuneBagMapper.selectByPrimaryKey(id);
    }


    @Override
    public int save(YgFortuneBag ygFortuneBag) {
        return ygFortuneBagMapper.insertSelective(ygFortuneBag);
    }

    @Override
    public int update(YgFortuneBag ygFortuneBag) {
        return ygFortuneBagMapper.updateByPrimaryKeySelective(ygFortuneBag);
    }

    @Override
    public ResultSet<FortuneBagVo> search(QueryInfo queryInfo, String productName) {
        int total = ygFortuneBagMapper.countSuper(productName);
        if (total == 0) {
            return new ResultSet<>();
        }
        List<FortuneBagVo> result = ygFortuneBagMapper.selectSuper(queryInfo, productName);
        return new ResultSet<>(total, result);
    }

    @Override
    public ResultSet<FortuneBagDetailVo> searchDetail(QueryInfo queryInfo, String batchNo, String skuCode) {
        int total = ygFortuneBagMapper.countDetailSuper(batchNo, skuCode);
        if (total == 0) {
            return new ResultSet<>();
        }
        List<FortuneBagDetailVo> result = ygFortuneBagMapper.selectDetailSuper(queryInfo, batchNo, skuCode);
        return new ResultSet<>(total, result);
    }

    @Override
    public List<YgFortuneBag> findFortuneBagListWithStock(String batchNo, List<String> skuCodeList, Boolean hasStock) {
        return ygFortuneBagMapper.selectFortuneBagListWithStock(batchNo, skuCodeList, hasStock);
    }

    @Override
    public int deleteSoft(Long[] ids) {
        Assert.notEmpty(ids);
        YgFortuneBagExample example = new YgFortuneBagExample();
        example.createCriteria().andIdIn(Arrays.asList(ids));
        YgFortuneBag record = new YgFortuneBag();
        record.setStatus(DataStatus.Delete);
        return ygFortuneBagMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int deleteSoft(Long id) {
        return this.deleteSoft(new Long[]{id});
    }

    @Override
    public int saveOrUpdate(YgFortuneBag ygFortuneBag) {
        int r;
        if (ygFortuneBag.getId() != null) {
            r = this.update(ygFortuneBag);
        } else {
            r = this.save(ygFortuneBag);
        }
        return r;
    }

    @Override
    public Message saveBatch(List<YgFortuneBag> fortuneBagList, String handler) {
        try {
            this.validateParamForSave(fortuneBagList, handler);
        } catch (Exception e) {
            e.printStackTrace();
            return Message.error(e.getMessage(), null);
        }
        String batchNo = fortuneBagList.get(0).getBatchNo();
        String skuCode = fortuneBagList.get(0).getSkuCode();
        List<YgFortuneBag> listFromDb = this.findFortuneBagListWithStock(batchNo, Collections.singletonList(skuCode), null);
        List<YgFortuneBag> insertList = new ArrayList<>();
        List<YgFortuneBag> updateList = new ArrayList<>();

        if (CollectionUtils.isEmpty(listFromDb)) {
            listFromDb = new ArrayList<>();
        }
        Map<String, List<YgFortuneBag>> collect = listFromDb.stream().collect(Collectors.groupingBy(YgFortuneBag::getSrcSkuCode));
        fortuneBagList.forEach(fortuneBag -> {
            List<YgFortuneBag> list = collect.get(fortuneBag.getSrcSkuCode());
            if (CollectionUtils.isNotEmpty(list)) {
                fortuneBag.setId(list.get(0).getId());
                updateList.add(fortuneBag);
            } else {
                fortuneBag.setCreateBy(fortuneBag.getUpdateBy());
                fortuneBag.setCreateTime(fortuneBag.getUpdateTime());
                fortuneBag.setStockCount(0);
                insertList.add(fortuneBag);
            }
        });
        Map<String, List<YgFortuneBag>> collect1 = fortuneBagList.stream().collect(Collectors.groupingBy(YgFortuneBag::getSrcSkuCode));
        listFromDb.forEach(fortuneBag -> {
            if (!collect1.containsKey(fortuneBag.getSrcSkuCode())) {
                YgFortuneBag record = new YgFortuneBag();
                record.setId(fortuneBag.getId());
                record.setStatus(DataStatus.Delete);
                updateList.add(record);
            }
        });
        this.insertBatch(insertList);
        this.updateBatch(updateList);
        return Message.success(null);
    }

    @Override
    public List<YgFortuneBag> resolveDataFromExcel(List<Map<Integer, Object>> excelInfo) {
        Assert.notEmpty(excelInfo, "excel数据为空。");
        List<String> skuCodeList = new ArrayList<>();
        List<YgFortuneBag> fortuneBagList = new ArrayList<>();
        for (Map<Integer, Object> infoMap : excelInfo) {
            YgFortuneBag fortuneBag = processInfoFromExcelRow(infoMap);
            this.validateBagInfoFromExcel(fortuneBag, skuCodeList);
            fortuneBagList.add(fortuneBag);
        }
        this.validateBagInfoByExistsSku(fortuneBagList, skuCodeList);
        return fortuneBagList;
    }

    @Override
    public List<FortuneBagVo> findFortuneBagInfoByCopy(String skuCode) {
        return ygFortuneBagMapper.selectBagInfoByCopy(skuCode);
    }

    @Override
    public List<FortuneBagDetailVo> findFortuneBagDetailByCopy(String batchNo, String skuCode, String sizeName) {
        return ygFortuneBagMapper.selectBagDetailByCopy(batchNo, skuCode, sizeName);
    }

    /**
     * 校验福袋SKU和发货SKU是否存在
     *
     * @param fortuneBagList 产品信息
     * @param skuCodeList    skuCodeList
     */
    private void validateBagInfoByExistsSku(List<YgFortuneBag> fortuneBagList, List<String> skuCodeList) {
        if (CollectionUtils.isEmpty(skuCodeList)) {
            return;
        }
        List<SkuBasicData> skuList = ygSkuService.getBasicDataBySkuCode(PromotionType.Ordinary, skuCodeList.toArray(new String[0]));
        List<String> existsList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(skuList)) {
            List<String> list = skuList.stream().map(SkuBasicData::getSkuCode).collect(Collectors.toList());
            existsList.addAll(list);
        }
        fortuneBagList.forEach(fortuneBag -> {
            StringBuilder errMsg = new StringBuilder(fortuneBag.getErrMsg() == null ? "" : fortuneBag.getErrMsg());
            if (!existsList.contains(fortuneBag.getSkuCode())) {
                errMsg.append("福袋SKU编码不存在；");
            }
            if (!existsList.contains(fortuneBag.getSrcSkuCode())) {
                errMsg.append("发货SKU编码不存在；");
            }
            if (errMsg.length() > 0) {
                fortuneBag.setErrMsg(errMsg.toString());
            }
        });
    }

    /**
     * 校验基础信息
     *
     * @param fortuneBag  产品信息
     * @param skuCodeList skuCodeList
     */
    private void validateBagInfoFromExcel(YgFortuneBag fortuneBag, List<String> skuCodeList) {
        StringBuilder errMsg = new StringBuilder();
        if (StringUtils.isBlank(fortuneBag.getSkuCode())) {
            errMsg.append("福袋SKU编码为空；");
        } else {
            skuCodeList.add(fortuneBag.getSkuCode());
        }
        if (fortuneBag.getBagSkuCount() == null) {
            errMsg.append("福袋发货商品总数为空；");
        }
        if (fortuneBag.getGroup() == null) {
            errMsg.append("集合为空；");
        }
        if (fortuneBag.getCount() == null) {
            errMsg.append("件数为空；");
        }
        if (fortuneBag.getPriority() == null) {
            errMsg.append("发货优先级为空；");
        }
        if (StringUtils.isBlank(fortuneBag.getSrcSkuCode())) {
            errMsg.append("发货SKU编码为空；");
        } else {
            skuCodeList.add(fortuneBag.getSrcSkuCode());
        }
        if (errMsg.length() > 0) {
            fortuneBag.setErrMsg(errMsg.toString());
        }
    }

    /**
     * 处理excel每行数据
     *
     * @param infoMap excel每行数据
     * @return
     */
    private YgFortuneBag processInfoFromExcelRow(Map<Integer, Object> infoMap) {
        YgFortuneBag bag = new YgFortuneBag();
        infoMap.forEach((key, val) -> {
            DecimalFormat df = new DecimalFormat("0");
            switch (key) {
                case 0:
                    String skuCode = val == null ? null : Long.valueOf(df.format(val)).toString();
                    bag.setSkuCode(skuCode);
                    break;
                case 1:
                    Integer bagSkuCount = val == null ? null : Integer.valueOf(df.format(val));
                    bag.setBagSkuCount(bagSkuCount);
                    break;
                case 2:
                    Integer group = val == null ? null : Integer.valueOf(df.format(val));
                    bag.setGroup(group);
                    break;
                case 3:
                    Integer count = val == null ? null : Integer.valueOf(df.format(val));
                    bag.setCount(count);
                    break;
                case 4:
                    Integer priority = val == null ? null : Integer.valueOf(df.format(val));
                    bag.setPriority(priority);
                    break;
                case 5:
                    String srcSkuCode = val == null ? null : Long.valueOf(df.format(val)).toString();
                    bag.setSrcSkuCode(srcSkuCode);
                    break;
                default:
                    break;
            }
        });
        return bag;
    }

    private void updateBatch(List<YgFortuneBag> updateList) {
        new AbstractSplitListTemplate<YgFortuneBag>(updateList) {
            @Override
            public int execute(List<YgFortuneBag> recordList) {
                return ygFortuneBagMapper.updateBatch(recordList);
            }
        }.split();
    }

    private void insertBatch(List<YgFortuneBag> insertList) {
        new AbstractSplitListTemplate<YgFortuneBag>(insertList) {
            @Override
            public int execute(List<YgFortuneBag> recordList) {
                return ygFortuneBagMapper.insertBatch(recordList);
            }
        }.split();
    }

    /**
     * 校验参数
     *
     * @param fortuneBagList 数据信息
     * @param handler        操作人
     */
    private void validateParamForSave(List<YgFortuneBag> fortuneBagList, String handler) {
        Assert.notEmpty(fortuneBagList, "福袋产品明细不能为空");
        String batchNo = fortuneBagList.get(0).getBatchNo();
        if (StringUtil.isBlank(batchNo)) {
            batchNo = DateConvertUtils.format(new Date());
        }
        for (YgFortuneBag fortuneBag : fortuneBagList) {
            Assert.isTrue(StringUtils.isNotBlank(fortuneBag.getSkuCode()), "福袋产品skuCode不能为空");
            Assert.isTrue(StringUtils.isNotBlank(fortuneBag.getSrcSkuCode()), "福袋产品明细商品srcSkuCode不能为空");
            Assert.notNull(fortuneBag.getGroup(), "福袋产品明细商品分组group不能为空");
            Assert.notNull(fortuneBag.getCount(), "福袋产品明细商品选定数count不能为空");
            Assert.notNull(fortuneBag.getPriority(), "福袋产品明细商品优先级priority不能为空");
            Assert.notNull(fortuneBag.getBagSkuCount(), "福袋发货商品总数bagSkuCount不能为空");
            fortuneBag.setUpdateTime(new Date());
            fortuneBag.setUpdateBy(handler);
            fortuneBag.setBatchNo(batchNo);
        }
    }

}

